/*
//定时器实现左右移动流水灯
#include<reg52.h>
sbit ADDR0=P1^0;
sbit ADDR1=P1^1;
sbit ADDR2=P1^2;
sbit ADDR3=P1^3;
sbit ENLED=P1^4;
void main()
{
    unsigned char count=0;
    unsigned char shift=0x01;//赋初值
    unsigned char dir=0;
    ADDR0=0;
    ADDR1=1;
    ADDR2=1;
    ADDR3=1;
    ENLED=0;

    TMOD=0x01;
    TH0=0xB8;// 12/11059200(Hz)*N=20ms  65536-18432(N)=47104  0xB800
    TL0=0x00;
    TR0=1;
    while(1)
    {
        P0=~shift;//P0初值 1111 1110
        while(TF0==1)//溢出时  while(TF0==0);不溢出就死循环 也可以  
        {
            TF0=0;//溢出 清零 
            TH0=0xB8;//0.02s 的时钟周期
            TL0=0x00;
            count++;
            if(count>=10)//0.02*10=0.2s
            {
                count=0;
                if(dir==0)
                {
                    shift=shift<<1;
                    if(shift==0x80)
                    {
                        dir=1;
                    }
                }
                else
                {
                    shift=shift>>1;
                    if(shift==0x01)
                    {
                        dir=0;
                    }
                }
            }
        } 
    }
}
*/



/*
//数码管静态显示 倒计时
#include <reg52.h>

sbit ADDR0 = P1^0;
sbit ADDR1 = P1^1;
sbit ADDR2 = P1^2;
sbit ADDR3 = P1^3;
sbit ENLED = P1^4;

//用数组来存储数码管的真值表
unsigned char code LedChar[] = {
    0xC0, 0xF9, 0xA4, 0xB0, 0x99, 0x92, 0x82, 0xF8,
    0x80, 0x90, 0x88, 0x83, 0xC6, 0xA1, 0x86, 0x8E
};

void main()
{
    unsigned char cnt = 0;  //记录T0中断次数
    unsigned char sec = 0x0F;  //记录经过的秒数

    ENLED = 0;    //使能U3，选择数码管DS1
    ADDR3 = 1;
    ADDR2 = 0;
    ADDR1 = 0;
    ADDR0 = 0;
    TMOD = 0x01;  //设置T0为模式1
    TH0  = 0xB8;  //为T0赋初值0xB800
    TL0  = 0x00;
    TR0  = 1;     //启动T0
    
    while (1)
    {
        if (TF0 == 1)        //判断T0是否溢出
        {
            TF0 = 0;         //T0溢出后，清零中断标志
            TH0 = 0xB8;      //并重新赋初值
            TL0 = 0x00;
            cnt++;           //计数值自加1
            if (cnt >= 50)   //判断T0溢出是否达到50次
            {
                cnt = 0;            //达到50次后计数值清零
                P0 = LedChar[sec];  //当前秒数对应的真值表中的值送到P0口
                sec--;   //秒数大于0时，减一
                if (sec==0 )  //秒数等于0时，重新赋值    
                {
                   sec=0x0F;  
                }
            }
        }
    }
}
*/


/*
//动态数码管000000->999999 十进制
#include <reg52.h>

sbit ADDR0 = P1^0;
sbit ADDR1 = P1^1;
sbit ADDR2 = P1^2;
sbit ADDR3 = P1^3;
sbit ENLED = P1^4;

//用数组来存储数码管的真值表
unsigned char code LedChar[] = {
    0xC0, 0xF9, 0xA4, 0xB0, 0x99, 0x92, 0x82, 0xF8,
    0x80, 0x90, 0x88, 0x83, 0xC6, 0xA1, 0x86, 0x8E
};
//六个数码管缓冲区；确保初值不显示
unsigned char LedBuff[6]={
    0xFF,0xFF,0xFF,0xFF,0xFF,0xFF
};

void main()
{
    unsigned char i=0;
    unsigned int cnt = 0;  //记录T0中断次数  char 255    int 65535
    unsigned long sec = 0;  //记录经过的秒数

    ENLED = 0;    //使能U3
    ADDR3 = 1;
    TMOD = 0x01;  //设置T0为模式1
    //1ms    X*12/11059200=0.001s
    //X=921     65536-921=64615   为T0赋初值 0XFC67
    TH0  = 0xFC;  
    TL0  = 0x67;
    TR0  = 1;     //启动T0
    
    while (1)
    {
        if (TF0 == 1)        //判断T0是否溢出
        {
            TF0 = 0;         //T0溢出后，清零中断标志
            TH0 = 0xFC;      //并重新赋初值
            TL0 = 0x67;
            cnt++;           //计数值自加1
            if (cnt >= 1000)   //判断T0溢出是否达到50次   =1s
            {
                cnt = 0;            //达到50次后计数值清零
                sec++;   //秒数大于0时，加一
                LedBuff[0]=LedChar[sec%10];//6个数码管依次显示
                LedBuff[1]=LedChar[sec/10%10];
                LedBuff[2]=LedChar[sec/100%10];
                LedBuff[3]=LedChar[sec/1000%10];
                LedBuff[4]=LedChar[sec/10000%10];
                LedBuff[5]=LedChar[sec/100000%10];
            }
            if(i==0)   //i表示第几个数码管
            {ADDR0=0;ADDR1=0;ADDR2=0;i++;P0=LedBuff[0];}
            else if(i==1)
            {ADDR0=1;ADDR1=0;ADDR2=0;i++;P0=LedBuff[1];}
            else if(i==2)
            {ADDR0=0;ADDR1=1;ADDR2=0;i++;P0=LedBuff[2];}
            else if(i==3)
            {ADDR0=1;ADDR1=1;ADDR2=0;i++;P0=LedBuff[3];}
            else if(i==4)
            {ADDR0=0;ADDR1=0;ADDR2=1;i++;P0=LedBuff[4];}
            else if(i==5)
            {ADDR0=1;ADDR1=0;ADDR2=1;i=0;P0=LedBuff[5];}
        }
    }
}
*/



/*
//switch 语句
#include <reg52.h>

sbit ADDR0 = P1^0;
sbit ADDR1 = P1^1;
sbit ADDR2 = P1^2;
sbit ADDR3 = P1^3;
sbit ENLED = P1^4;

//用数组来存储数码管的真值表
unsigned char code LedChar[] = {
    0xC0, 0xF9, 0xA4, 0xB0, 0x99, 0x92, 0x82, 0xF8,
    0x80, 0x90, 0x88, 0x83, 0xC6, 0xA1, 0x86, 0x8E
};
//六个数码管缓冲区；确保初值不显示
unsigned char LedBuff[6]={
    0xFF,0xFF,0xFF,0xFF,0xFF,0xFF
};

void main()
{
    unsigned char i=0;
    unsigned int cnt = 0;  //记录T0中断次数  char 255    int 65535
    unsigned long sec = 0;  //记录经过的秒数

    ENLED = 0;    //使能U3
    ADDR3 = 1;
    TMOD = 0x01;  //设置T0为模式1
    //1ms    X*12/11059200=0.001s
    //X=921     65536-921=64615   为T0赋初值 0XFC67
    TH0  = 0xFC;  
    TL0  = 0x67;
    TR0  = 1;     //启动T0
    
    while (1)
    {
        if (TF0 == 1)        //判断T0是否溢出
        {
            TF0 = 0;         //T0溢出后，清零中断标志
            TH0 = 0xFC;      //并重新赋初值
            TL0 = 0x67;
            cnt++;           //计数值自加1
            if (cnt >= 1000)   //判断T0溢出是否达到50次   =1s
            {
                cnt = 0;            //达到50次后计数值清零
                sec++;   //秒数大于0时，加一
                LedBuff[0]=LedChar[sec%10];//6个数码管依次显示
                LedBuff[1]=LedChar[sec/10%10];
                LedBuff[2]=LedChar[sec/100%10];
                LedBuff[3]=LedChar[sec/1000%10];
                LedBuff[4]=LedChar[sec/10000%10];
                LedBuff[5]=LedChar[sec/100000%10];
            }
            switch(i)
            {
                case 0:ADDR0=0;ADDR1=0;ADDR2=0;i++;P0=LedBuff[0];break;
                case 1:ADDR0=1;ADDR1=0;ADDR2=0;i++;P0=LedBuff[1];break;
                case 2:ADDR0=0;ADDR1=1;ADDR2=0;i++;P0=LedBuff[2];break;
                case 3:ADDR0=1;ADDR1=1;ADDR2=0;i++;P0=LedBuff[3];break;
                case 4:ADDR0=0;ADDR1=0;ADDR2=1;i++;P0=LedBuff[4];break;
                case 5:ADDR0=1;ADDR1=0;ADDR2=1;i=0;P0=LedBuff[5];break;
                default:break;
            }
        }
    }
}
*/


/*
//鬼影以及抖动解决     delay() 会消耗单片机的时间 亮度降低
// 比如 先开控制第一个数码管亮 位选信号1，然后送 数字1 的 段选信号，
// 这个时候第一个数码管就成功的显示了数字1了，这个时候我关掉第一个数码管的位选信号，
// 打开第二位的 位选信号2，在这一瞬间，二号数码管等于收到了 位选信号2和 段选信号1，
// 短暂的亮了一下数字1，接下来段选信号刷新，更新为段选信号2，数码管改显示2。 
// 因为段选信号跟位选信号同步更新的成本太高，所以人们想出了一个从程序上解决这个问题的思路，即消隐操作。。。
// 就是位选信号更新前（上一位位选引脚锁存，下一位位选引脚未打开之间）
// 先送一个0x00或者0xff出来，刷新掉段选信号上的数据，这样的话，等下一个管子可以被点亮时，段选数据实际是空的。。。

#include <reg52.h>

sbit ADDR0 = P1^0;
sbit ADDR1 = P1^1;
sbit ADDR2 = P1^2;
sbit ADDR3 = P1^3;
sbit ENLED = P1^4;

//用数组来存储数码管的真值表
unsigned char code LedChar[] = {
    0xC0, 0xF9, 0xA4, 0xB0, 0x99, 0x92, 0x82, 0xF8,
    0x80, 0x90, 0x88, 0x83, 0xC6, 0xA1, 0x86, 0x8E
};
//六个数码管缓冲区；确保初值不显示
unsigned char LedBuff[6]={
    0xFF,0xFF,0xFF,0xFF,0xFF,0xFF
};

void main()
{
    unsigned char i=0;
    unsigned int cnt = 0;  //记录T0中断次数  char 255    int 65535
    unsigned long sec = 0;  //记录经过的秒数

    ENLED = 0;    //使能U3
    ADDR3 = 1;
    TMOD = 0x01;  //设置T0为模式1
    //1ms    X*12/11059200=0.001s
    //X=921     65536-921=64615   为T0赋初值 0XFC67
    TH0  = 0xFC;  
    TL0  = 0x67;
    TR0  = 1;     //启动T0
    
    while (1)
    {
        if (TF0 == 1)        //判断T0是否溢出
        {
            TF0 = 0;         //T0溢出后，清零中断标志
            TH0 = 0xFC;      //并重新赋初值
            TL0 = 0x67;
            cnt++;           //计数值自加1
            if (cnt >= 1000)   //判断T0溢出是否达到50次   =1s
            {
                cnt = 0;            //达到50次后计数值清零
                sec++;   //秒数大于0时，加一
                LedBuff[0]=LedChar[sec%10];//6个数码管依次显示
                LedBuff[1]=LedChar[sec/10%10];
                LedBuff[2]=LedChar[sec/100%10];
                LedBuff[3]=LedChar[sec/1000%10];
                LedBuff[4]=LedChar[sec/10000%10];
                LedBuff[5]=LedChar[sec/100000%10];
                //加一的时候抖动  这一段也占用时间 引入中断
                //底下那段是高等级任务 先执行      中断-----改变任务等级(看作闹铃，如一边烧水一边看电视)
                //TF 定时器溢出标志 中断 也是寄存器  
            }
            P0=0xFF;//解决鬼影  1关闭段选     // 2 关闭位选 74HC138全输出高电平  ENLED=1;
            switch(i)
            {
                case 0:ADDR0=0;ADDR1=0;ADDR2=0;i++;P0=LedBuff[0];break;
                case 1:ADDR0=1;ADDR1=0;ADDR2=0;i++;P0=LedBuff[1];break;
                case 2:ADDR0=0;ADDR1=1;ADDR2=0;i++;P0=LedBuff[2];break;//产生鬼影例子 在这个时刻瞬态 
                //ADDR0切换到0；但ADDR1还保持0在一瞬间 相当于case0在一瞬间亮一下 给了case2一个错误的数
                case 3:ADDR0=1;ADDR1=1;ADDR2=0;i++;P0=LedBuff[3];break;
                case 4:ADDR0=0;ADDR1=0;ADDR2=1;i++;P0=LedBuff[4];break;
                case 5:ADDR0=1;ADDR1=0;ADDR2=1;i=0;P0=LedBuff[5];break;
                default:break;
            }
            // 2 关闭位选 74HC138全输出高电平  续前ENLED=0;
        }
    }
}
*/



/*
//加入中断 EA 总开关    ET0定时器0中断使能
#include <reg52.h>

sbit ADDR0 = P1^0;
sbit ADDR1 = P1^1;
sbit ADDR2 = P1^2;
sbit ADDR3 = P1^3;
sbit ENLED = P1^4;

//用数组来存储数码管的真值表
unsigned char code LedChar[] = {
    0xC0, 0xF9, 0xA4, 0xB0, 0x99, 0x92, 0x82, 0xF8,
    0x80, 0x90, 0x88, 0x83, 0xC6, 0xA1, 0x86, 0x8E
};
//六个数码管缓冲区；确保初值不显示
unsigned char LedBuff[6]={
    0xFF,0xFF,0xFF,0xFF,0xFF,0xFF
};

unsigned char i=0;
unsigned int cnt = 0;  
unsigned char flag1s=0;

void main()
{
    unsigned long sec = 0;  //记录经过的秒数

    ENLED = 0;    //使能U3
    ADDR3 = 1;
    TMOD = 0x01;  //设置T0为模式1
    //1ms    X*12/11059200=0.001s
    //X=921     65536-921=64615   为T0赋初值 0XFC67
    TH0  = 0xFC;  
    TL0  = 0x67;
    TR0  = 1;     //启动T0
    EA=1; //EA 总开关    
    ET0=1; //ET0定时器0中断使能
    while (1)
    {
        if(flag1s==1)
        {
            flag1s=0;
            sec++;
            LedBuff[0]=LedChar[sec%10];//6个数码管依次显示
            LedBuff[1]=LedChar[sec/10%10];
            LedBuff[2]=LedChar[sec/100%10];
            LedBuff[3]=LedChar[sec/1000%10];
            LedBuff[4]=LedChar[sec/10000%10];
            LedBuff[5]=LedChar[sec/100000%10];
            //加一的时候抖动  这一段也占用时间 引入中断
            //底下那段是高等级任务 先执行      中断-----改变任务等级(看作闹铃，如一边烧水一边看电视)
            //TF 定时器溢出标志 中断 也是寄存器  
        }
    }
}
void InterruptTimer0() interrupt 1 //定义函数后加关键字 interrupt 1    中断函数不需要调用，达到条件自动进入
{                                     //计算 中断函数编号 X*8+3=11 中断向量地址0x000B   X=1
    TH0=0xFC;
    TL0=0x67;
    cnt++;
    if(cnt>=1000)
    {
        cnt=0;
        flag1s=1;   //设置1s定时标志
    }
    //1ms动态刷新一次
    P0=0xFF;//解决鬼影  1关闭段选     // 2 关闭位选 74HC138全输出高电平  ENLED=1;
    switch(i)
    {
        case 0:ADDR0=0;ADDR1=0;ADDR2=0;i++;P0=LedBuff[0];break;
        case 1:ADDR0=1;ADDR1=0;ADDR2=0;i++;P0=LedBuff[1];break;
        case 2:ADDR0=0;ADDR1=1;ADDR2=0;i++;P0=LedBuff[2];break;//产生鬼影例子 在这个时刻瞬态 
        //ADDR0切换到0；但ADDR1还保持0在一瞬间 相当于case0在一瞬间亮一下 给了case2一个错误的数
        case 3:ADDR0=1;ADDR1=1;ADDR2=0;i++;P0=LedBuff[3];break;
        case 4:ADDR0=0;ADDR1=0;ADDR2=1;i++;P0=LedBuff[4];break;
        case 5:ADDR0=1;ADDR1=0;ADDR2=1;i=0;P0=LedBuff[5];break;
        default:break;
    }
    // 2 关闭位选 74HC138全输出高电平  续前鬼影 ENLED=0;
}
*/


/*
//高位不显示0
#include <reg52.h>

sbit ADDR0 = P1^0;
sbit ADDR1 = P1^1;
sbit ADDR2 = P1^2;
sbit ADDR3 = P1^3;
sbit ENLED = P1^4;

//用数组来存储数码管的真值表
unsigned char code LedChar[] = {
    0xC0, 0xF9, 0xA4, 0xB0, 0x99, 0x92, 0x82, 0xF8,
    0x80, 0x90, 0x88, 0x83, 0xC6, 0xA1, 0x86, 0x8E
};
//六个数码管缓冲区；确保初值不显示
unsigned char LedBuff[6]={
    0xFF,0xFF,0xFF,0xFF,0xFF,0xFF
};

unsigned char i=0;
unsigned int cnt = 0;  //中断次数
unsigned char flag1s=0; //1s定时标志

void main()
{
    unsigned long sec = 0;  //记录经过的秒数
    char j=0; //循环变量  初始化与不初始化都行
    unsigned char buf[6]=0; //中间转换缓冲区  初始化与不初始化都行

    ENLED = 0;    //使能U3
    ADDR3 = 1;
    TMOD = 0x01;  //设置T0为模式1
    //1ms    X*12/11059200=0.001s
    //X=921     65536-921=64615   为T0赋初值 0XFC67
    TH0  = 0xFC;  
    TL0  = 0x67;
    TR0  = 1;     //启动T0
    EA=1; //EA 总开关    
    ET0=1; //ET0定时器0中断使能
    while (1)
    {
        if(flag1s==1)
        {
            flag1s=0;
            sec++;
            //将sec按十进制提取到buf数组中
            buf[0]=sec%10;//6个数码管依次显示
            buf[1]=sec/10%10;
            buf[2]=sec/100%10;
            buf[3]=sec/1000%10;
            buf[4]=sec/10000%10;
            buf[5]=sec/100000%10;
            //加一的时候抖动  这一段也占用时间 引入中断
            //底下那段是高等级任务 先执行      中断-----改变任务等级(看作闹铃，如一边烧水一边看电视)
            //TF 定时器溢出标志 中断 也是寄存器  

            //从最高位开始，遇到0不显示，遇到非0退出循环
            for(j=5;j>=0;j--)  //j在这里初始化
            {
                if(buf[j]==0)
                    LedBuff[j]=0xFF;
                else
                    break;
            }
            //将剩余有效数字转换
            for(;j>=0;j--) //for()起始未对j操作，j保持是个循环结束的值
            {
                LedBuff[j]=LedChar[buf[j]];
            }
        }
    }
}

//定时器0中断服务
void InterruptTimer0() interrupt 1 //定义函数后加关键字 interrupt 1    中断函数不需要调用，达到条件自动进入
{                                     //计算 中断函数编号 X*8+3=11 中断向量地址0x000B   X=1
    TH0=0xFC;
    TL0=0x67;
    cnt++;
    if(cnt>=1000)
    {
        cnt=0;
        flag1s=1;   //设置1s定时标志
    }
    //1ms动态刷新一次
    P0=0xFF;//解决鬼影  1关闭段选     // 2 关闭位选 74HC138全输出高电平  ENLED=1;
    switch(i)
    {
        case 0:ADDR0=0;ADDR1=0;ADDR2=0;i++;P0=LedBuff[0];break;
        case 1:ADDR0=1;ADDR1=0;ADDR2=0;i++;P0=LedBuff[1];break;
        case 2:ADDR0=0;ADDR1=1;ADDR2=0;i++;P0=LedBuff[2];break;//产生鬼影例子 在这个时刻瞬态 
        //ADDR0切换到0；但ADDR1还保持0在一瞬间 相当于case0在一瞬间亮一下 给了case2一个错误的数
        case 3:ADDR0=1;ADDR1=1;ADDR2=0;i++;P0=LedBuff[3];break;
        case 4:ADDR0=0;ADDR1=0;ADDR2=1;i++;P0=LedBuff[4];break;
        case 5:ADDR0=1;ADDR1=0;ADDR2=1;i=0;P0=LedBuff[5];break;
        default:break;
    }
    // 2 关闭位选 74HC138全输出高电平  续前鬼影 ENLED=0;
}
*/




//倒计时   定时器1中断
#include <reg52.h>

sbit ADDR0 = P1^0;
sbit ADDR1 = P1^1;
sbit ADDR2 = P1^2;
sbit ADDR3 = P1^3;
sbit ENLED = P1^4;

//用数组来存储数码管的真值表
unsigned char code LedChar[] = {
    0xC0, 0xF9, 0xA4, 0xB0, 0x99, 0x92, 0x82, 0xF8,
    0x80, 0x90, 0x88, 0x83, 0xC6, 0xA1, 0x86, 0x8E
};
//六个数码管缓冲区；确保初值不显示
unsigned char LedBuff[6]={
    0xFF,0xFF,0xFF,0xFF,0xFF,0xFF
};

unsigned char i=0;
unsigned int cnt = 0;  //中断次数
unsigned char flag1s=0; //1s定时标志

void main()
{
    unsigned long sec = 1000000;  //记录经过的秒数，倒计时加1
    char j=0; //循环变量  初始化与不初始化都行
    unsigned char buf[6]=0; //中间转换缓冲区  初始化与不初始化都行

    ENLED = 0;    //使能U3
    ADDR3 = 1;
    TMOD = 0x10;  //设置T1为模式1
    //1ms    X*12/11059200=0.001s
    //X=921     65536-921=64615   为T0赋初值 0XFC67
    TH1  = 0xFC;  
    TL1  = 0x67;
    TR1  = 1;     //启动T0
    EA=1; //EA 总开关    
    ET1=1; //定时器1中断使能
    while (1)
    {
        if(flag1s==1)
        {
            flag1s=0;
            sec--;
            //将sec按十进制提取到buf数组中
            buf[0]=sec%10;//6个数码管依次显示
            buf[1]=sec/10%10;
            buf[2]=sec/100%10;
            buf[3]=sec/1000%10;
            buf[4]=sec/10000%10;
            buf[5]=sec/100000%10;
            //加一的时候抖动  这一段也占用时间 引入中断
            //底下那段是高等级任务 先执行      中断-----改变任务等级(看作闹铃，如一边烧水一边看电视)
            //TF 定时器溢出标志 中断 也是寄存器  

            //从最高位开始，遇到0不显示，遇到非0退出循环
            for(j=5;j>=0;j--)  //j在这里初始化
            {
                if(buf[j]==0)
                    LedBuff[j]=0xFF;
                else
                    break;
            }
            //将剩余有效数字转换
            for(;j>=0;j--) //for()起始未对j操作，j保持是个循环结束的值
            {
                LedBuff[j]=LedChar[buf[j]];
            }
        }
    }
}

//定时器1中断服务
void InterruptTimer1() interrupt 3 //定义函数后加关键字 interrupt 3    中断函数不需要调用，达到条件自动进入
{                                     //计算 中断函数编号 X*8+3=27 中断向量地址0x001B   X=3
    TH1=0xFC;
    TL1=0x67;
    cnt++;
    if(cnt>=1000)
    {
        cnt=0;
        flag1s=1;   //设置1s定时标志
    }
    //1ms动态刷新一次
    P0=0xFF;//解决鬼影  1关闭段选     // 2 关闭位选 74HC138全输出高电平  ENLED=1;
    switch(i)
    {
        case 0:ADDR0=0;ADDR1=0;ADDR2=0;i++;P0=LedBuff[0];break;
        case 1:ADDR0=1;ADDR1=0;ADDR2=0;i++;P0=LedBuff[1];break;
        case 2:ADDR0=0;ADDR1=1;ADDR2=0;i++;P0=LedBuff[2];break;//产生鬼影例子 在这个时刻瞬态 
        //ADDR0切换到0；但ADDR1还保持0在一瞬间 相当于case0在一瞬间亮一下 给了case2一个错误的数
        case 3:ADDR0=1;ADDR1=1;ADDR2=0;i++;P0=LedBuff[3];break;
        case 4:ADDR0=0;ADDR1=0;ADDR2=1;i++;P0=LedBuff[4];break;
        case 5:ADDR0=1;ADDR1=0;ADDR2=1;i=0;P0=LedBuff[5];break;
        default:break;
    }
    // 2 关闭位选 74HC138全输出高电平  续前鬼影 ENLED=0;
}